package com.jmex.model.ogredotscene.loader;

import com.jme.math.Vector3f;
import com.jme.scene.CameraNode;
import com.jme.scene.state.LightState;
import com.jme.system.DisplaySystem;
import com.jmex.model.ModelFormatException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import javax.xml.bind.JAXBException;
import com.jme.util.resource.ResourceLocatorTool;
import com.jmex.model.ogredotscene.gen.Camera;
import com.jmex.model.ogredotscene.gen.Entity;
import com.jmex.model.ogredotscene.gen.Light;
import com.jmex.model.ogredotscene.gen.Node;
import com.jmex.model.ogredotscene.gen.Nodes;
import com.jmex.model.ogredotscene.gen.Position;
import com.jmex.model.ogredotscene.gen.Quaternion;
import com.jmex.model.ogredotscene.gen.Scale;
import com.jmex.model.ogredotscene.util.XMLUtil;


public class NodesLoader {
    private static final String NODE_NAME = "Node";
    private static final String XMLFILE_ENDING = ".xml";
    private OgreLoader ogreLoader;
    private com.jme.scene.Node jmeScene;
    private LightState lightState;


    public void buildNodes(Nodes dotNodes, com.jme.scene.Node jmeScene) throws JAXBException, URISyntaxException, IOException, ModelFormatException {

        for (Node dotNode : dotNodes.getNode()) {
            com.jme.scene.Node jmeNode = new com.jme.scene.Node();

            if (!dotNode.getName().isEmpty()) {
                jmeNode.setName(dotNode.getName() + NODE_NAME);
            }
            generateNode(dotNode, jmeNode);
            jmeScene.attachChild(jmeNode);
        }
    }

    public com.jme.scene.Node generateNode(Node dotNode, com.jme.scene.Node jmeNode) throws IOException, ModelFormatException {
        /*  Objects of the following type(s) are allowed in the list
         * {@link Plane }
         * {@link BillboardSet }
         * {@link TrackTarget }
         * {@link Entity }
         * {@link Light }
         * {@link Node  x }
         * {@link LookTarget }
         * {@link Quaternion }
         * {@link UserDataReference }
         * {@link ParticleSystem }
         * {@link Position }
         * {@link Scale }
         * {@link Camera }
         * {@link Orientation }
         */

        Node nodeInNode = findInList(dotNode.getPositionOrOrientationOrQuaternion(), Node.class);
        if (nodeInNode != null) {
            generateNode(nodeInNode, jmeNode);
        }

        Camera camera = findInList(dotNode.getPositionOrOrientationOrQuaternion(), Camera.class);
        if (camera != null) {
            CameraNode cameraNode = new CameraNode(camera.getName(), DisplaySystem.getDisplaySystem().getRenderer().getCamera());
            if (camera.getPosition() != null) {
                cameraNode.setLocalTranslation(new Vector3f(XMLUtil.getFloatString(camera.getPosition().getX()), XMLUtil.getFloatString(camera.getPosition().getY()), XMLUtil.getFloatString(camera.getPosition().getZ())));
            }

            if (camera.getQuaternion() != null) {
                com.jme.math.Quaternion jmeQuaternion = new com.jme.math.Quaternion(XMLUtil.getFloatString(camera.getQuaternion().getX()), XMLUtil.getFloatString(camera.getQuaternion().getY()), XMLUtil.getFloatString(camera.getQuaternion().getZ()), XMLUtil.getFloatString(camera.getQuaternion().getW()));
                cameraNode.setLocalRotation(jmeQuaternion);
            }
            jmeNode.attachChild(new CameraNode());
        }

        Light light = findInList(dotNode.getPositionOrOrientationOrQuaternion(), Light.class);
        if (light != null) {
            LightLoader lightLoader = new LightLoader();
            lightLoader.setLightState(lightState);
            lightLoader.addLight(light);
        }

        Entity entity = findInList(dotNode.getPositionOrOrientationOrQuaternion(), Entity.class);
        if (entity != null) {
            URL resourceUrl = ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_MODEL, entity.getMeshFile() + XMLFILE_ENDING);
            jmeNode.attachChild(ogreLoader.loadModel(resourceUrl, entity.getName()));
        }

        Position position = findInList(dotNode.getPositionOrOrientationOrQuaternion(), Position.class);
        if (position != null) {
            jmeNode.setLocalTranslation(XMLUtil.getFloatString(position.getX()), XMLUtil.getFloatString(position.getY()), XMLUtil.getFloatString(position.getZ()));
        }

        Scale scale = findInList(dotNode.getPositionOrOrientationOrQuaternion(), Scale.class);
        if (scale != null) {
            Vector3f vector3f = new Vector3f(XMLUtil.getFloatDouble(scale.getX()), XMLUtil.getFloatDouble(scale.getY()), XMLUtil.getFloatDouble(scale.getZ()));
            jmeNode.setLocalScale(vector3f);
        }

        Quaternion dotSceneQuaternion = findInList(dotNode.getPositionOrOrientationOrQuaternion(), Quaternion.class);
        if (dotSceneQuaternion != null) {
            com.jme.math.Quaternion jmeQuaternion = new com.jme.math.Quaternion();
            jmeQuaternion.setW(XMLUtil.getFloatString(dotSceneQuaternion.getW()));
            jmeQuaternion.setX(XMLUtil.getFloatString(dotSceneQuaternion.getX()));
            jmeQuaternion.setY(XMLUtil.getFloatString(dotSceneQuaternion.getY()));
            jmeQuaternion.setZ(XMLUtil.getFloatString(dotSceneQuaternion.getZ()));
            jmeNode.setLocalRotation(jmeQuaternion);
        }

        return jmeNode;
    }

    public com.jme.scene.Node getJmeScene() {
        return jmeScene;
    }

    public void setJmeScene(com.jme.scene.Node jmeScene) {
        this.jmeScene = jmeScene;
    }

    private <T> T findInList(List<?> list, Class<T> clazz) {
        for (Object o : list) {
            if (clazz.isInstance(o)) {
                return clazz.cast(o);
            }
        }
        return null;
    }

    public OgreLoader getOgreLoader() {
        return ogreLoader;
    }

    public void setOgreLoader(OgreLoader ogreLoader) {
        this.ogreLoader = ogreLoader;
    }

    public LightState getLightState() {
        return lightState;
    }

    public void setLightState(LightState lightState) {
        this.lightState = lightState;
    }
}
